package ddz.net;

import ch.qos.logback.classic.Logger;
import com.kaka.notice.Command;
import com.kaka.notice.Message;
import ddz.constants.Crypto;
import ddz.constants.ErrCode;
import ddz.constants.ErrLevel;
import ddz.constants.OpCode;
import ddz.utils.AES;
import ddz.utils.DES;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.slf4j.LoggerFactory;

/**
 * 网络通信数据包处理器<br>
 * 数据包中继站<br>
 * 亦可做数据包过滤器，防止未经登录随意发送数据包
 *
 * @author zkpursuit
 */
public class ProtocolMessageHandler extends Command implements WsSender {

    private final Logger logger = (Logger) LoggerFactory.getLogger(ProtocolMessageHandler.class);

    /**
     * 直接放行的数据协议号
     */
    private static final int cmds[] = new int[]{
            Integer.parseInt(OpCode.cmd_login),
            Integer.parseInt(OpCode.cmd_rebind),
            Integer.parseInt(OpCode.cmd_heart_beat),
            Integer.parseInt(OpCode.cmd_recovery)
    };

    @Override
    public void execute(Message msg) {
        ProtocolMessage nm = (ProtocolMessage) msg;
        WebSocketFrame frame = (WebSocketFrame) nm.getBody();
        if (!(frame instanceof BinaryWebSocketFrame)) return;
        ByteBuf data = frame.content();
        int cryptoType = data.readByte();
        int opcode = 0;
        byte[] bytes;
        if (cryptoType == 0) {
            opcode = data.readInt();
        }
        bytes = new byte[data.readableBytes()];
        data.readBytes(bytes);
        if (cryptoType != 0) {
            if (cryptoType == 1) {
                bytes = DES.decrypt(bytes, Crypto.NET_DES_KEY_BYTES);
            } else if (cryptoType == 2) {
                bytes = AES.decrypt(bytes, Crypto.NET_AES_KEY_BYTES);
            }
            data.writeBytes(bytes);
            opcode = data.readInt();
            bytes = new byte[data.readableBytes()];
            data.readBytes(bytes);
        }

        boolean passFlag = false;   //协议放行标志
        for (int _cmd : cmds) {
            if (_cmd == opcode) {
                passFlag = true;
                break;
            }
        }

        Long uid = null;
        if (!passFlag) {
            uid = (Long) CtxManager.getBindId(nm.ctx);
            if (uid == null || uid == 0) {
                this.sendError(nm.ctx, opcode, ErrLevel.ERROR, ErrCode.illegal_request);
                return;
            }
        }

        if (opcode != 99 && logger.isInfoEnabled()) {
            logger.info("用户{}操作>>协议号：{}", uid, opcode);
        }

        if (opcode != cmds[1]) { //不为心跳时为信道绑定最后收到信息的时间戳
            if (nm.ctx != null) {
                long[] received = nm.ctx.channel().attr(CtxManager.bind_received).get();
                if (received != null && received.length == 2) {
                    int prevOpcode = (int) received[0];
                    if (prevOpcode == opcode) {
                        long offset = System.currentTimeMillis() - received[1];
                        if (offset <= 500) {
                            //this.sendError(nm.ctx, opcode, ErrLevel.WARN, ErrCode.frequent_operate);
                            return;
                        }
                    }
                    received[0] = opcode;
                    received[1] = System.currentTimeMillis();
                } else {
                    received = new long[]{opcode, System.currentTimeMillis()};
                    nm.ctx.channel().attr(CtxManager.bind_received).set(received);
                }
            }
        }

        if (!this.getFacade().hasCommand(opcode)) {
            this.sendError(nm.ctx, opcode, ErrLevel.WARN, ErrCode.interface_disenable);
            return;
        }

        nm.setWhat(opcode);
        nm.setData(bytes);
        sendMessage(nm);
    }

}
